/*----------------------------------------------------------------------------
Owner(s): Shane Whitfield
$Copyright: $
$Id: $
----------------------------------------------------------------------------*/

#include "engine.h"
#include "world.h"
#include "gomgr.h"
#include "camera.h"
#include "timermgr.h"
#include "visrep.h"
#include "texture.h"
#include "intro.h"
#include "nncommand.h"
#include "map.h"
#include "player.h"
#include "nodemgr.h"
#include "soundmgr.h"
#include "touchmgr.h"
#include "uimgr.h"


/* -------------------------------------------------------------------------*/
//globals
static void (*s_systemMessage)(const char* title, const char* message, const char* acceptString, const char* cancelString) = 0 ;
static bool (*s_systemMessageShowing)() = 0 ;

/* -------------------------------------------------------------------------*/
void CEngine::SystemMessage(const char* i_title, const char* i_message, const char* i_acceptString, const char* i_cancelString)
{
	s_systemMessage(i_title, i_message, i_acceptString, i_cancelString);
}

bool CEngine::IsSystemMessageShowing() const
{
	return s_systemMessageShowing();
}

void CEngine::SetSystemMessageShowing(bool (*systemMessageShowing)())
{
	s_systemMessageShowing = systemMessageShowing;
}

void CEngine::SetSystemMessage(void (*systemMessage)(const char* title, const char* message, const char* acceptString, const char* cancelString))
{
    s_systemMessage = systemMessage;
}

CEngine::CEngine() : super("CEngine")
{
	init();
	
	m_state = EState_SettingUp;
	m_isIntroRequested = false;
}

void CEngine::init()
{
	//add all subsystems
#if DEBUG
	AddChildSubsystem(new CNNCommand());
#endif //DEBUG
	AddChildSubsystem(new CTouchMgr());
	AddChildSubsystem(new CTextureMgr());
	AddChildSubsystem(new CUIMgr());
	AddChildSubsystem(new CWorld());
	AddChildSubsystem(new CSoundMgr());
	AddChildSubsystem(new CTimeMgr());
	
	AddChildSubsystem(new CCamera());
	AddChildSubsystem(new CGoMgr());
	AddChildSubsystem(new CIntro());
	AddChildSubsystem(new CMapMgr());
	AddChildSubsystem(new CNodeMgr());
	
	//singletons non-subsystems
	new CPlayer();
    	
	// init all subsystems
	DispatchInit();

	// post-init all subsystems now that the .bsu is up
	DispatchPostInit();
}

void CEngine::Render()
{
	switch(m_state)
	{
	case EState_Intro:
		{
			g_intro.Render();
			DispatchPostIntroRender();
		}
		break;
	case EState_Map:
		{
			g_mapmgr.Render();
			DispatchPostMapRender();
		}
		break;
	case EState_Running:
		{
			g_world.Render();

			DispatchPostWorldRender();
		}
		break;
	}
}

void CEngine::Release()
{

}

#if DEBUG
void CEngine::NNCommand(const char* i_commandTakerName, const char* i_commandFunction, const char* i_parameters)
{
	g_nncommand.HandleCommand(i_commandTakerName, i_commandFunction, i_parameters);
}
#endif

void CEngine::Update(float i_dt)
{
	for(;;)
	{
		EState prevState = m_state;
		switch(m_state)
		{
		case EState_SettingUp:
			{
				setState(EState_Intro);
			}
			break;
		case EState_Intro:
			{
				g_timemgr.Update(i_dt);
				
				DispatchPreIntroUpdate();
				g_intro.Update();
				DispatchPostIntroUpdate();
				
				if (g_mapmgr.IsMapRequested())
				{
					setState(EState_Map);
				}
			}
			break;
		case EState_Map:
			{
				DispatchPreMapUpdate();
				g_mapmgr.Update();
				DispatchPostMapUpdate();
				
				if (g_world.HasPendingWorldRequest())
				{
					setState(EState_PreUnload);
				}
			}
			break;
		case EState_PreLoad:
			{
				setState(EState_Load);
			}
			break;
		case EState_Load:
			{
				setState(EState_PostLoad);
			}
			break;
		case EState_PostLoad:
			{
				setState(EState_Running);
			}
			break;
		case EState_Running:
			{
				//keep going till there is a request?
				g_timemgr.Update(i_dt);

				DispatchPreWorldUpdate();
				g_world.Update();
				DispatchPostWorldUpdate();
				
				if (g_world.HasPendingWorldRequest() || m_isIntroRequested || g_mapmgr.IsMapRequested())
				{
					setState(EState_PreUnload);
				}
			}
			break;
		case EState_PreUnload:
			{
				setState(EState_Unload);
			}
			break;
		case EState_Unload:
			{
				setState(EState_PostUnload);
			}
			break;
		case EState_PostUnload:
			{
				if (m_isIntroRequested)
				{
					//go back to the entro
					setState(EState_Intro);
				}
				else if (g_mapmgr.IsMapRequested())
				{
					setState(EState_Map);
				}
				else if (g_world.HasPendingWorldRequest())
				{
					setState(EState_PreLoad);
				}
			}
			break;
		}
		
		if (prevState == m_state)
		{
			break;
		}
	}
		
}

void CEngine::setState(EState i_state)
{
	m_state = i_state;
	
	switch(m_state)
	{
	case EState_Intro:
		{
			g_intro.Activate();
			m_isIntroRequested = false;
		}
		break;
	case EState_Map:
		{
			g_mapmgr.Activate();
		}
		break;
	case EState_PreLoad:
		{
			// notify before the load
			DispatchPreWorldLoad();
		}
		break;
	case EState_Load:
		{
			// do the load
			g_world.LoadPendingWorld();
		}
		break;
	case EState_PostLoad:
		{
			// notify the load is done
			DispatchPostWorldLoad();

			// do the postload
			g_world.PostLoad();
		}
		break;
	case EState_PreUnload:
		{
			// notify before the unload
			DispatchPreWorldUnload();
		}
		break;
	case EState_Unload:
		{
			// do the unload
			g_world.Unload();
		}
		break;
	case EState_PostUnload:
		{
			// notify the unload is done
			DispatchPostWorldUnload();
		}
		break;
	}

}

/*-----------------------------------EOF!-----------------------------------*/ 
